package com.zudada.servermain.exception;



import com.zudada.servermain.POJO.enums.Result;
import com.zudada.servermain.POJO.enums.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;

/**
 * 全局异常异常处理
 *
 * @author Chopper
 */
@RestControllerAdvice
@Slf4j
public class GlobalControllerExceptionHandler {

    /**
     * 如果超过长度，则前后段交互体验不佳，使用默认错误消息
     */
    static Integer MAX_LENGTH = 200;

    /**
     * 自定义异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public Result handleServiceException(HttpServletRequest request, final Exception e, HttpServletResponse response) {


        //如果是自定义异常，则获取异常，返回自定义错误消息
        if (e instanceof ServiceException) {
            ServiceException serviceException = ((ServiceException) e);
            ResultCode resultCode = serviceException.getResultCode();

            Integer code = null;
            String message = null;

            if (resultCode != null) {
                code = resultCode.code();
                message = resultCode.message();
            }
            //如果有扩展消息，则输出异常中，跟随补充异常
            if (!serviceException.getMsg().equals(ServiceException.DEFAULT_MESSAGE)) {
                message += ":" + serviceException.getMsg();
            }

            log.error("全局异常[ServiceException]:{}-{}", serviceException.getResultCode().code(), serviceException.getResultCode().message(), e);
            return Result.error(code,message);

        } else {

            log.error("全局异常[ServiceException]:", e);
        }

        //默认错误消息
        String errorMsg = "服务器异常，请稍后重试";
        if (e != null && e.getMessage() != null && e.getMessage().length() < MAX_LENGTH) {
            errorMsg = e.getMessage();
        }
        return Result.error(ResultCode.ERROR.code(), errorMsg);
    }

    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public Result handleBusinessException(HttpServletRequest request, BusinessException e, HttpServletResponse response) {
        log.warn("业务异常[BusinessException]: {}", e.getMessage());
        return Result.error(ResultCode.PARAMS_ERROR.code(), e.getMessage());
    }

    /**
     * bean校验未通过异常 - 用于@RequestBody参数验证
     *
     * @see javax.validation.Valid
     * @see org.springframework.validation.Validator
     * @see org.springframework.validation.DataBinder
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> methodArgumentNotValidExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e, HttpServletResponse response) {
        log.warn("参数验证异常[MethodArgumentNotValidException]: {}", e.getMessage());
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        if (!fieldErrors.isEmpty()) {
            FieldError error = fieldErrors.get(0);
            return Result.error(ResultCode.PARAMS_ERROR.code(), error.getDefaultMessage());
        }
        return Result.error(ResultCode.PARAMS_ERROR.code(), ResultCode.PARAMS_ERROR.message());
    }

    /**
     * bean校验未通过异常 - 用于表单参数验证
     *
     * @see javax.validation.Valid
     * @see org.springframework.validation.Validator
     * @see org.springframework.validation.DataBinder
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> bindExceptionHandler(HttpServletRequest request, BindException e, HttpServletResponse response) {
        log.warn("参数验证异常[BindException]: {}", e.getMessage());
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        if (!fieldErrors.isEmpty()) {
            FieldError error = fieldErrors.get(0);
            return Result.error(ResultCode.PARAMS_ERROR.code(), error.getDefaultMessage());
        }
        return Result.error(ResultCode.PARAMS_ERROR.code(), ResultCode.PARAMS_ERROR.message());
    }

    /**
     * bean校验未通过异常 - 用于方法参数验证
     *
     * @see javax.validation.Valid
     * @see org.springframework.validation.Validator
     * @see org.springframework.validation.DataBinder
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> constraintViolationExceptionHandler(HttpServletRequest request, ConstraintViolationException e, HttpServletResponse response) {
        log.warn("参数验证异常[ConstraintViolationException]: {}", e.getMessage());
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        if (!violations.isEmpty()) {
            ConstraintViolation<?> violation = violations.iterator().next();
            return Result.error(ResultCode.PARAMS_ERROR.code(), violation.getMessage());
        }
        return Result.error(ResultCode.PARAMS_ERROR.code(), ResultCode.PARAMS_ERROR.message());
    }
    /**
     * 处理数据库异常（如外键约束、唯一约束等）
     */
    @ExceptionHandler(org.springframework.dao.DataIntegrityViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> dataIntegrityViolationExceptionHandler(HttpServletRequest request, org.springframework.dao.DataIntegrityViolationException e, HttpServletResponse response) {
        log.error("数据库完整性约束异常[DataIntegrityViolationException]: {}", e.getMessage(), e);
        String errorMsg = "操作失败，数据存在关联关系，无法删除";
        if (e.getMessage() != null && e.getMessage().contains("foreign key")) {
            errorMsg = "删除失败，该港口存在关联数据，请先删除关联数据";
        } else if (e.getMessage() != null && e.getMessage().contains("unique")) {
            errorMsg = "操作失败，数据已存在";
        }
        return Result.error(ResultCode.PARAMS_ERROR.code(), errorMsg);
    }

    /**
     * 处理其他运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> runtimeExceptionHandler(HttpServletRequest request, RuntimeException e, HttpServletResponse response) {
        log.error("运行时异常[RuntimeException]: {}", e.getMessage(), e);
        String errorMsg = "操作失败，请稍后重试";
        if (e.getMessage() != null && e.getMessage().length() < MAX_LENGTH) {
            errorMsg = e.getMessage();
        }
        return Result.error(ResultCode.ERROR.code(), errorMsg);
    }
    //
//    @ExceptionHandler(RuntimeException.class)
//    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
//    public Result<Object> runtimeExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) {
//
//        log.error("全局异常[RuntimeException]:", e);
//
//        return Result.error(ResultCode.ERROR.code(),ResultCode.ERROR.message());
//    }
//
//
//
//    /**
//     * bean校验未通过异常
//     *
//     * @see javax.validation.Valid
//     * @see org.springframework.validation.Validator
//     * @see org.springframework.validation.DataBinder
//     */
//    @ExceptionHandler(BindException.class)
//    @ResponseStatus(HttpStatus.BAD_REQUEST)
//    @ResponseBody
//    public Result<Object> validExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) {
//
//        BindException exception = (BindException) e;
//        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
//        for (FieldError error : fieldErrors) {
//            return Result.error(ResultCode.PARAMS_ERROR.code(), error.getDefaultMessage());
//        }
//        return Result.error(ResultCode.PARAMS_ERROR.code(),ResultCode.PARAMS_ERROR.message());
//    }
//
//    /**
//     * bean校验未通过异常
//     *
//     * @see javax.validation.Valid
//     * @see org.springframework.validation.Validator
//     * @see org.springframework.validation.DataBinder
//     */
//    @ExceptionHandler(ConstraintViolationException.class)
//    @ResponseStatus(HttpStatus.BAD_REQUEST)
//    @ResponseBody
//    public Result<Object> constraintViolationExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) {
//        ConstraintViolationException exception = (ConstraintViolationException) e;
//        return Result.error(ResultCode.PARAMS_ERROR.code(), exception.getMessage());
//    }

}
